package top.hcode.hoj.service.admin;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.nutz.http.Header;
import org.nutz.http.Http;
import org.nutz.http.Response;
import org.nutz.json.Json;
import org.nutz.lang.util.NutMap;
import org.sagacity.sqltoy.model.MapKit;
import org.springframework.stereotype.Service;
import top.hcode.hoj.common.LazyDao;
import top.hcode.hoj.dao.OrgClassDao;
import top.hcode.hoj.pojo.dto.SyncSchoolDTO;
import top.hcode.hoj.pojo.dto.TyOrgSyncDTO;
import top.hcode.hoj.pojo.entity.org.OrgUser;
import top.hcode.hoj.pojo.entity.org.TyOrg;
import top.hcode.hoj.service.LockService;
import top.hcode.hoj.tyedu.SyncSchoolOrgService;
import top.hcode.hoj.tyedu.SyncSchoolUserService;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 天喻组织数据同步服务
 *
 * @author orangej
 * @since 2025-09-03
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TyOrgSyncService {

    private final LazyDao lazyDao;
    private final SyncSchoolOrgService syncSchoolOrgService;
    private final SyncSchoolUserService syncSchoolUserService;
    private final OrgClassDao orgClassDao;
    private final LockService lockService;

    private static final String LOCK_KEY = "ty_org_sync_lock";
    private static final int LOCK_TIMEOUT = 3600; // 1小时超时

    public boolean isSyncInProgress() {
        return lockService.isLocked(LOCK_KEY);
    }

    public void syncAndExport(TyOrgSyncDTO syncDTO) {
        // 获取分布式锁
        if (!lockService.tryLock(LOCK_KEY, LOCK_TIMEOUT)) {
            throw new RuntimeException("系统正在执行同步任务，请稍后再试");
        }

        try {
            log.info("开始执行天喻数据同步任务, 学校数量: {}", syncDTO.getSchools().size());

            // 按学校处理
            for (SyncSchoolDTO school : syncDTO.getSchools()) {
                try {
                    processSingleSchool(school);
                    log.info("学校处理完成: {}", school.getSchoolName());
                } catch (Exception e) {
                    log.error("学校处理失败，跳过该学校: {}, 错误: {}", school.getSchoolName(), e.getMessage(), e);
                }
            }

            log.info("天喻数据同步和导出任务完成");

        } finally {
            // 释放锁
            lockService.releaseLock(LOCK_KEY);
        }
    }

    /**
     * 处理单个学校的同步和导出
     */
    private void processSingleSchool(SyncSchoolDTO school) {
        log.info("开始处理学校: {}, tyOrgId: {}", school.getSchoolName(), school.getTyOrgId());

        // 解析校区ID列表
        List<String> rawIdList = Arrays.stream(school.getTyOrgId().split(",")).map(String::trim).collect(Collectors.toList());

        // 处理校区列表，如果包含学校ID，则展开为所有下级校区
        List<String> campusIdList = expandCampusIdList(rawIdList);

        // 找到顶层学校ID（取第一个ID对应的学校）
        String schoolId = findTopSchool(rawIdList.get(0));

        log.info("开始同步学校: {}, 校区列表: {}", schoolId, campusIdList);

        // 1. 天喻数据同步（按学校为单位）
        syncSchoolData(schoolId);

        // 2. 数据导出到bookshare（按校区为单位）
        for (String campusId : campusIdList) {
            try {
                log.info("开始导出校区数据: {}", campusId);
                exportCampusData(campusId, school.getSchoolName(), school.getGradeName(), school.getClassName());
            } catch (Exception e) {
                log.error("校区数据导出失败，跳过该校区: {}, 错误: {}", campusId, e.getMessage(), e);
            }
        }
    }

    /**
     * 展开校区ID列表，如果包含学校ID，则将其下级所有校区加进来
     */
    private List<String> expandCampusIdList(List<String> rawIdList) {
        Set<String> expandedIdSet = new LinkedHashSet<>();

        for (String orgId : rawIdList) {
            TyOrg org = lazyDao.selectOne(TyOrg.class, "select * from ty_org where id = ?", orgId);
            if (org == null) {
                log.warn("未找到组织信息: {}", orgId);
                continue;
            }

            if (org.getOrgType() == 2) {
                // 如果是学校，查找其下级所有校区
                List<String> subCampusIds = lazyDao.queryString(
                        "select id from ty_org where parent_id = ? and org_type = 3", orgId);
                if (subCampusIds.isEmpty()) {
                    // 如果没有下级校区，则使用学校本身
                    expandedIdSet.add(orgId);
                } else {
                    // 添加所有下级校区
                    expandedIdSet.addAll(subCampusIds);
                }
            } else {
                // 如果不是学校，直接添加
                expandedIdSet.add(orgId);
            }
        }

        List<String> result = new ArrayList<>(expandedIdSet);
        log.info("展开校区ID列表: {} -> {}", rawIdList, result);
        return result;
    }

    /**
     * 找到组织的顶层学校
     */
    private String findTopSchool(String orgId) {
        TyOrg org = lazyDao.selectOne(TyOrg.class, "select * from ty_org where id = ?", orgId);
        if (org == null) {
            throw new RuntimeException("找不到组织: " + orgId);
        }

        if (org.getOrgType() == 2) {
            return org.getId();
        }

        if (StrUtil.isBlank(org.getParentId())) {
            throw new RuntimeException("无法找到组织的顶层学校: " + orgId);
        }

        return findTopSchool(org.getParentId());
    }

    /**
     * 同步学校数据（复用TyDownloadOrgApp逻辑）
     */
    private void syncSchoolData(String schoolId) {
        try {
            // 同步年级、班级信息
            syncSchoolOrgService.syncSchool(schoolId);

            // 重建班级
            orgClassDao.rebuildOrgClass();

            // 同步学生、教师信息
            syncSchoolUserService.syncSchoolUser(schoolId);

            // 更新 gmt_modified
            lazyDao.runSql("update ty_org set gmt_modified = now() where id = ?", schoolId);

            log.info("学校数据同步完成: {}", schoolId);
        } catch (Exception e) {
            log.error("学校数据同步失败: {}", schoolId, e);
            throw e; // 重新抛出，让上层处理
        }
    }

    /**
     * 导出校区数据到bookshare（复用OrgUserExportApp逻辑）
     */
    private void exportCampusData(String campusId, String schoolName, String gradeName, String className) {
        try {
            // 导出学生数据
            exportStudentData(campusId, schoolName, gradeName, className);

            // 导出教师数据
            exportTeacherData(campusId, schoolName, gradeName, className);

            log.info("校区数据导出完成: {}", campusId);
        } catch (Exception e) {
            log.error("校区数据导出失败: {}", campusId, e);
            throw e; // 重新抛出，让上层处理
        }
    }

    /**
     * 导出学生数据到bookshare
     */
    private void exportStudentData(String campusId, String schoolName, String gradeName, String className) {
        String campusCode = lazyDao.fetchString("select tree_code from org where ty_org_id = ?", campusId);
        if (StrUtil.isBlank(campusCode)) {
            log.warn("未找到校区tree_code: {}", campusId);
            return;
        }

        // 构建查询条件
        List<String> classIdList = lazyDao.queryString(
                "select id from org where tree_code like :campusCode and org_type = 7 " +
                "#[and org_name like :gradeName] #[and org_name like :className]",
                MapKit.startOf("campusCode", campusCode)
                        .of("gradeName", gradeName)
                        .endOf("className", className));

        if (CollUtil.isEmpty(classIdList)) {
            log.info("未找到符合条件的班级, 跳过学生导出");
            return;
        }

        // 学生账号
        List<OrgUser> orgUserList = lazyDao.selectList(OrgUser.class,
                "select * from org_user t0 where user_type = 0 and " +
                "exists (select 1 from class_has_user where user_id = t0.id and org_id in (?))", classIdList);

        if (CollUtil.isEmpty(orgUserList)) {
            log.info("未找到需要同步的学生数据");
            return;
        }

        AtomicInteger count = new AtomicInteger(0);
        orgUserList.parallelStream().forEach(orgUser -> {
            try {
                List<String> classNameList = lazyDao.queryString(
                        "select org_name from org where " +
                        "id in (select distinct org_id from class_has_user where user_id = ? and tree_code like ?)",
                        orgUser.getId(), campusCode + "%");

                NutMap user = NutMap.NEW()
                        .addv("userType", 2)
                        .addv("uname", orgUser.getRealName())
                        .addv("username", orgUser.getUsername())
                        .addv("gender", getGenderCode(orgUser.getGender()))
                        .addv("avatarUrl", orgUser.getAvatar())
                        .addv("mobile", orgUser.getMobile());

                NutMap data = NutMap.NEW().addv("user", user)
                        .addv("schoolName", schoolName)
                        .addv("classNameList", classNameList);

                Response response = Http.post3("https://console-prod.rui-ya.com/api/import-ty-user",
                        Json.toJson(data),
                        Header.create(NutMap.NEW().addv("Content-Type", "application/json")),
                        60000);
                String content = response.getContent();
                if ("ok".equals(content)) {
                    lazyDao.runSql("update org_user set flag0 = 1 where id = ?", orgUser.getId());
                } else {
                    log.error("学生数据导出失败: {}, 响应: {}", orgUser.getUsername(), content);
                }

                int current = count.getAndIncrement();
                if (current % 100 == 0) {
                    log.info("学生数据导出进度: {} / {}", current, orgUserList.size());
                }
            } catch (Exception e) {
                log.error("处理学生数据失败: {}", orgUser.getUsername(), e);
            }
        });

        log.info("学生数据导出完成, 总计: {}", orgUserList.size());
    }

    /**
     * 导出教师数据到bookshare
     */
    private void exportTeacherData(String campusId, String schoolName, String gradeName, String className) {
        String campusCode = lazyDao.fetchString("select tree_code from org where ty_org_id = ?", campusId);
        if (StrUtil.isBlank(campusCode)) {
            log.warn("未找到校区tree_code: {}", campusId);
            return;
        }

        // 教师账号
        List<OrgUser> orgUserList = lazyDao.selectList(OrgUser.class,
                "select * from org_user where id in (" +
                "select distinct user_id from class_has_user where user_type = 1 and org_id in (" +
                "select id from org_class where org_class.tree_code like ?))", campusCode + "%");

        if (CollUtil.isEmpty(orgUserList)) {
            log.info("未找到需要同步的教师数据");
            return;
        }

        AtomicInteger count = new AtomicInteger(0);
        orgUserList.parallelStream().forEach(orgUser -> {
            try {
                // 同一个学校的所有班级
                List<String> classNameList = lazyDao.queryString(
                        "select distinct org_name from org where " +
                        "id in (select distinct org_id from class_has_user where user_id = ? and tree_code like ?)",
                        orgUser.getId(), campusCode.substring(0, 4) + "%");

                NutMap user = NutMap.NEW()
                        .addv("userType", 1)
                        .addv("uname", orgUser.getRealName())
                        .addv("username", orgUser.getUsername())
                        .addv("gender", getGenderCode(orgUser.getGender()))
                        .addv("avatarUrl", orgUser.getAvatar())
                        .addv("mobile", orgUser.getMobile());

                NutMap data = NutMap.NEW().addv("user", user)
                        .addv("schoolName", schoolName)
                        .addv("classNameList", classNameList);

                Response response = Http.post3("https://console-prod.rui-ya.com/api/import-ty-user",
                        Json.toJson(data),
                        Header.create(NutMap.NEW().addv("Content-Type", "application/json")),
                        60000);
                String content = response.getContent();
                if ("ok".equals(content)) {
                    lazyDao.runSql("update org_user set flag0 = 1 where id = ?", orgUser.getId());
                } else {
                    log.error("教师数据导出失败: {}, 响应: {}", orgUser.getUsername(), content);
                }

                int current = count.getAndIncrement();
                if (current % 100 == 0) {
                    log.info("教师数据导出进度: {} / {}", current, orgUserList.size());
                }
            } catch (Exception e) {
                log.error("处理教师数据失败: {}", orgUser.getUsername(), e);
            }
        });

        log.info("教师数据导出完成, 总计: {}", orgUserList.size());
    }

    /**
     * 获取性别代码
     */
    private static String getGenderCode(Integer gender) {
        if (gender == null) {
            return "S"; // 保密
        }
        switch (gender) {
            case 0:
                return "F"; // 女
            case 1:
                return "M"; // 男
            default:
                return "S"; // 保密
        }
    }
}